我們在之前所有的範例中,都是把文本寫在檔案內,再由 parser 讀取之。這次我們直接在 terminal 輸入字串組,讓 parser 根據我們所輸入的內容做計算。
請實作出一個簡易的計算機,根據 terminal 輸入的內容做計算,並將答案顯示在 terminal 上。使用者可以輸入多條算式,或輸入 “exit” 結束程式。
%{
#include "main.h"
#include "yacc.tab.h"
%}
integer ([0-9]+)
float ([0-9]*\.?[0-9]+)
blank_chars ([ \f\r\t\v]+)
expressions ([-+*/()])
%%
{integer} { sscanf(yytext, "%d", &(yylval.intNum)); return INTEGER; }
{float} { sscanf(yytext, "%f", &(yylval.floatNum)); return FLOAT; }
{expressions} { return yytext[0]; }
{blank_chars} { ; }
"=" { return yytext[0]; }
\n { return yytext[0]; }
"exit" { return 0; }
%%
int yywrap(void) {
return 1;
}
%{
#include "main.h"
void yyerror(const char *s);
extern int yylex();
%}
%union {
float floatNum;
int intNum;
}
%token <intNum> INTEGER
%token <floatNum> FLOAT
%type <floatNum> value expr
%left '+' '-'
%left '*' '/'
%nonassoc UMINUS
%%
lines:
| lines expr '\n' { printf("Result: %f\n", $2); printf("Please insert an equation, or \"exit\" for exit.\n");}
;
expr:
value { $$ = $1; }
| expr '+' expr { $$ = $1 + $3; }
| expr '-' expr { $$ = $1 - $3; }
| expr '*' expr { $$ = $1 * $3; }
| expr '/' expr
{
if ($3 == 0.0) {
yyerror("Error: divisor cannot be zero!");
YYABORT;
} else {
$$ = $1 / $3;
}
}
| '-' expr %prec UMINUS { $$ = -$2; }
| '(' expr ')' { $$ = $2; }
;
value:
FLOAT { $$ = $1; }
| INTEGER { $$ = (float)$1; }
;
%%
void yyerror(const char *s) {
cerr << s << endl;
}
#ifndef MAIN_H
#define MAIN_H
#include <iostream>
#include <stdio.h>
using namespace std;
#define YYSTYPE int
#endif
#include "main.h"
#include "yacc.tab.h"
extern int yyparse(void);
int main()
{
printf("Please insert an equation, or \"exit\" for exit.\n");
yyparse();
return 0;
}
基本上來說,許多應用程式的 commaand line 都是用 Lex & Yacc 的架構去執行的,因此這個範例可以延伸到許多非常複雜的系統,原理大致是相同的。